/*
 * $Id: bookmarks.c 39 2008-07-11 00:27:47Z dtikhonov $
 *
 * Bookmarks implementation.
 */

#include <string.h>
#include <stdlib.h>

#include "bookmarks.h"
#include "misc.h"

typedef struct {
    lua_State *L;
} bctx_t;

static bool
_bms_get_bookmark_by_name (bms_t *self, const char *name, bookmark_t *bookmark)
{
    bctx_t *ctx = self->ctx;
    prepare_lua_method(ctx->L, "Bookmarks", "get_by_name");
    lua_getglobal(ctx->L, "_bookmarks");
    lua_pushstring(ctx->L, name);
    if (lua_pcall(ctx->L, 2, 1, 0) != 0)
        error(ctx->L, "error running Bookmarks:get_by_name: %s", lua_tostring(ctx->L, -1));
    if (lua_isnil(ctx->L, -1)) {
        lua_pop(ctx->L, 1);
        return false;
    }

    if (!lua_istable(ctx->L, -1)) {
        error(ctx->L, "%s: did not return a table");
    }

    lua_getfield(ctx->L, -1, "name");
    if (!lua_isstring(ctx->L, -1))
        error(ctx->L, "'name' is not a string: %d", lua_type(ctx->L, -1));
    bookmark->name = lua_tostring(ctx->L, -1);
    lua_pop(ctx->L, 1);
    lua_getfield(ctx->L, -1, "location");
    bookmark->cursor = lua_tointeger(ctx->L, -1);
    lua_pop(ctx->L, 2);
    return true;
}

static bool
_bms_add_bookmark (bms_t *self, const char *name, uint64_t cursor)
{
    bctx_t *ctx = self->ctx;
    prepare_lua_method(ctx->L, "Bookmarks", "add");
    lua_getglobal(ctx->L, "_bookmarks");
    lua_pushstring(ctx->L, name);
    lua_pushinteger(ctx->L, cursor);
    if (lua_pcall(ctx->L, 3, 0, 0) != 0)
        error(ctx->L, "error running Bookmarks:add: %s", lua_tostring(ctx->L, -1));
    return true;
}

static bool
_bms_get_bookmark_by_number (bms_t *self, int n, bookmark_t *bookmark)
{
    bctx_t *ctx = self->ctx;
    prepare_lua_method(ctx->L, "Bookmarks", "get_by_number");
    lua_getglobal(ctx->L, "_bookmarks");
    lua_pushinteger(ctx->L, n + 1);
    if (lua_pcall(ctx->L, 2, 1, 0) != 0)
        error(ctx->L, "error running Bookmarks:get_by_number: %s", lua_tostring(ctx->L, -1));
    if (lua_isnil(ctx->L, -1)) {
        lua_pop(ctx->L, 1);
        return false;
    }

    if (!lua_istable(ctx->L, -1)) {
        error(ctx->L, "%s: did not return a table");
    }

    lua_getfield(ctx->L, -1, "name");
    if (!lua_isstring(ctx->L, -1))
        error(ctx->L, "'name' is not a string: %d", lua_type(ctx->L, -1));
    bookmark->name = lua_tostring(ctx->L, -1);
    lua_pop(ctx->L, 1);
    lua_getfield(ctx->L, -1, "location");
    bookmark->cursor = lua_tointeger(ctx->L, -1);
    lua_pop(ctx->L, 2);

    return true;
}

static int
_bms_count (bms_t *self)
{
    bctx_t *ctx = self->ctx;
    prepare_lua_method(ctx->L, "Bookmarks", "count");
    lua_getglobal(ctx->L, "_bookmarks");
    if (lua_pcall(ctx->L, 1, 1, 0) != 0)
        error(ctx->L, "Error calling Bookmarks:count: %s",
                      lua_tostring(ctx->L, -1));
    int retval = lua_tonumber(ctx->L, -1);
    lua_pop(ctx->L, 1);
    return retval;
}

static void
_bms_delete_all (bms_t *self)
{
    bctx_t *ctx = self->ctx;
    prepare_lua_method(ctx->L, "Bookmarks", "delete_all");
    lua_getglobal(ctx->L, "_bookmarks");
    if (lua_pcall(ctx->L, 1, 1, 0) != 0)
        error(ctx->L, "Error calling Bookmarks:delete_all %s",
                      lua_tostring(ctx->L, -1));
    return;
}

static void
_bms_destroy (bms_t *self)
{
    self->delete_all(self);
    /* TODO: remove global '_bookmarks'? */
    free(self->ctx);
    free(self);
    return;
}

bms_t *
bms_new (lua_State *L)
{
    bctx_t *ctx = calloc(1, sizeof(*ctx));
    ctx->L = L;
    
    bms_t *self = calloc(1, sizeof(*self));
    self->ctx = ctx;

    self->destroy = _bms_destroy;
    self->get_bookmark_by_name = _bms_get_bookmark_by_name;
    self->get_bookmark_by_number = _bms_get_bookmark_by_number;
    self->add_bookmark = _bms_add_bookmark;
    self->delete_all = _bms_delete_all;
    self->count = _bms_count;

    return self;
}
